﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Inspire.DataStructures;
using Inspire.Entities;
using Inspire.Utility;
using Inspire.UIResources;
using System.Data;
using System.Data.Objects;
using System.Windows.Threading;
using System.ComponentModel;
using Inspire.Classes.Business;
using System;
using Inspire.Classes.Interfaces;
using Inspire.Classes.Common;

namespace Inspire.Pages
{
    /// <summary>
    /// Interaction logic for AddPatrons.xaml
    /// </summary>
    public partial class AddPatrons : Page, IPage
    {
        /// <summary>
        /// Get a reference to the PatronBusiness object.
        /// </summary>
        private PatronBusiness _patronBusiness = PatronBusiness.GetPatronBusiness();

        /// <summary>
        /// List backing the suggestions of Parent 1 field.
        /// </summary>
        private ObservableCollection<Patron> _parentList1 = new ObservableCollection<Patron>();
        public ObservableCollection<Patron> ParentList1
        {
            get
            {
                return this._parentList1;
            }
            set
            {
                this._parentList1 = value;
            }
        }

        /// <summary>
        /// List backing the suggestions of Parent 2 field.
        /// </summary>
        private ObservableCollection<Patron> _parentList2 = new ObservableCollection<Patron>();
        public ObservableCollection<Patron> ParentList2
        {
            get
            {
                return this._parentList2;
            }
            set
            {
                this._parentList2 = value;
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public AddPatrons()
        {
            CustomFieldBusiness customFieldBusiness = CustomFieldBusiness.GetCustomFieldBusiness();
            try
            {
                // Create the Custom Contact Field Types list for the user to create contact entries from
                this._contactFields = customFieldBusiness.GetCustomFieldTypesByCategory(Constants.CUSTOM_FIELD_PATRON_CONTACT); ;

                // Create the Custom Field Types structures list for the user to fill in
                foreach (CustomFieldType nextField in customFieldBusiness.GetCustomFieldTypesByCategory(Constants.CUSTOM_FIELD_PATRON_CUSTOM))
                {
                    NewCustomFieldSource newSource = new NewCustomFieldSource();
                    newSource.CustomFieldType = nextField;

                    this._customFields.Add(newSource);
                }
                InitializeComponent();
            }
            catch (Exception e)
            {
                Console.Out.WriteLine(e.Message);
                Console.Out.WriteLine(e.StackTrace);
            }
        }

        #region Basic Tab Fields

        // New Patron to Populate with Information
        private Patron _newPatron = new Patron();

        /// <summary>
        /// The New Patron Entity to be created and persisted
        /// </summary>
        public Patron NewPatron
        {
            get
            {
                return this._newPatron;
            }
            set
            {
                this._newPatron = value;
            }
        }

        #endregion

        #region Contact Tab Fields

        /// <summary>
        /// ContactFields: Expose the custom contact field types for patron contact information to the pageIndex.
        /// </summary>
        private List<CustomFieldType> _contactFields;
        public List<CustomFieldType> ContactFields
        {
            get
            {
                return this._contactFields;
            }
        }

        // List of Custom Contact Field Types and Values for this Patron
        private ObservableCollection<PatronContactMethod> _contactMethods = new ObservableCollection<PatronContactMethod>();

        /// <summary>
        /// The Contact Methods (Custom Contact Field Types and Values) for this Patron
        /// </summary>
        public ObservableCollection<PatronContactMethod> ContactMethods
        {
            get
            {
                return this._contactMethods;
            }
            set
            {
                this._contactMethods = value;
            }
        }

        #endregion

        #region Custom Tab Fields

        // List of Custom Fields for this Patron
        private ObservableCollection<NewCustomFieldSource> _customFields = new ObservableCollection<NewCustomFieldSource>();

        /// <summary>
        /// The Custom Field Type data structures for the Custom tab
        /// </summary>
        public ObservableCollection<NewCustomFieldSource> CustomFields
        {
            get
            {
                return this._customFields;
            }
            set
            {
                this._customFields = value;
            }
        }

        #endregion

        #region Event Handlers and General Methods

        /// <summary>
        /// Handle a button click for the Save button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            #region Validation
            // Validate all fields, even if unchanged
            if (!(errorProvider1.ValidateFinal()))
            {
                // Show a MessageBox with all errors
                string output = "";
                foreach (string error in this.errorProvider1.ErrorList)
                {
                    output += error + "\n";
                }

                // Display the Errors
                System.Windows.MessageBox.Show(output, "Validation Error", MessageBoxButton.OK, MessageBoxImage.Error);

                // Give Focus to the First Erroneous Field
                errorProvider1.FirstInvalidElement.Focus();

                // Exit this method to stop the save
                return;
            }
            #endregion

            #region Saving

            // Ensure a new Patron is returned. If not, alert the user.
            if (this._patronBusiness.AddPatron(this.NewPatron, this.CustomFields, this.ContactMethods) == null)
            {
                System.Windows.MessageBox.Show("An error occurred when saving. Please try saving again.", "Error.", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            dgCustomFields.Items.Refresh();

            #endregion

            #region Resetting
            
            // Forward the Reset  to the Reset() method
            this.NewPatron = new Patron();
            this.errorProvider1.DataContext = this.NewPatron;
            this.txtNotes.DataContext = this.NewPatron;
            this.Reset();

            #endregion
        }

        /// <summary>
        /// When the selection changes, look up the Patron ID for the selected person and set the Parent1 field of the new Patron to that ID.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void acParent_TextChanged(object sender, TextChangedEventArgs e)
        {
            int i = 0;
            AutoComplete parentAc = (AutoComplete)sender;
            IEnumerable<Patron> resultSet;
            string textValue = ((TextBox)e.Source).Text;
            string firstName = "", lastName = "";

            // Parse the text entered by the user
            for (i = 0; i < textValue.Length; i++)
            {
                if (textValue[i] == ' ') continue;

                if (lastName.Length > 0)
                {
                    firstName = textValue.Substring(i);
                    break;
                }

                if (textValue[i] == ',' || i == (textValue.Length - 1))
                {
                    lastName = textValue.Substring(0, i);
                    continue;
                }
            }

            // Update the option list based on a search with the user's text as the query
            resultSet = this._patronBusiness.SearchByName(firstName, lastName);
            if (resultSet != null && resultSet.Count() > 0)
            {
                parentAc.OptionList = resultSet.ToList<Object>();
                parentAc.ShowOptions = true;
            }
            else
            {
                parentAc.ShowOptions = false;
            }
        }

        /// <summary>
        /// Handle a button click for the Add Contact button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddContact_Click(object sender, RoutedEventArgs e)
        {
            PatronContactMethod newMethod = new PatronContactMethod();
            newMethod.MethodValue = "";

            this._contactMethods.Add(newMethod);
        }

        /// <summary>
        /// Handle the Cancel button being clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            // Forward the Reset command to the Reset() method
            this.Reset();
        }

        /// <summary>
        /// Handle a button click for the Remove Contact button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRemoveContact_Click(object sender, RoutedEventArgs e)
        {
            if (this.dgContactInformation.SelectedCells.Count > 0)
            {
                DataGridCell cell = DataGridHelper.GetCell(this.dgContactInformation.SelectedCells[0]);
                this._contactMethods.Remove((PatronContactMethod)DataGridHelper.GetRowItem(cell));
            }
        }

        /// <summary>
        /// If a cell is selected in our custom fields grid, activate it for editing.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgCustomFields_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
        {
            if (e.AddedCells.Count < 1) return;
            if (e.AddedCells[0].Column.DisplayIndex == 1)
            {
                dgCustomFields.BeginEdit();
            }
        }

        /// <summary>
        /// Handles switching tabs if user uses the nav buttons at the bottom of the screen
        /// </summary>
        /// <param name="sender">(Button) oject sending the event</param>
        /// <param name="e">(RoutedEventArgs) Arguments from the event</param>
        private void NavigateButtons_OnClick(object sender, RoutedEventArgs e)
        {
            // Handle Changing Tabs for Previous Button
            if (((Button)sender).Name.Equals("btnPrevious"))
            {
                // If it's already at the leftmost tab, do nothing
                if (this.tabControlAddPatrons.SelectedIndex == 0)
                {
                    return;
                }
                else
                {
                    // If the first tab is about to be shown, disable the Previous button
                    if (this.tabControlAddPatrons.SelectedIndex == 1)
                    {
                        this.btnPrevious.IsEnabled = false;

                        // Adjust the Text of the Previous Button
                        this.lblPreviousButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex - 1]).Header.ToString();
                    }
                    else
                    {
                        // Adjust the Text of the Previous Button
                        this.lblPreviousButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex - 2]).Header.ToString();
                    }

                    // Adjust the Text of the Next Button
                    this.lblNextButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex]).Header.ToString();

                    // Adjust the Visible Tab
                    this.tabControlAddPatrons.SelectedIndex = this.tabControlAddPatrons.SelectedIndex - 1;

                    // Ensure the Next Button is Enabled
                    this.btnNext.IsEnabled = true;
                }
            }

            // Handle Changing Tabs for the Next Button
            if (((Button)sender).Name.Equals("btnNext"))
            {
                // If it's already at the rightmost tab, do nothing
                if (this.tabControlAddPatrons.SelectedIndex == this.tabControlAddPatrons.Items.Count - 1)
                {
                    return;
                }
                else
                {
                    // If the last tab is about to be shown, disable the Next button
                    if (this.tabControlAddPatrons.SelectedIndex == (this.tabControlAddPatrons.Items.Count - 2))
                    {
                        this.btnNext.IsEnabled = false;

                        // Adjust the Text of the Next Button
                        this.lblNextButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex + 1]).Header.ToString();
                    }
                    else
                    {
                        // Adjust the Text of the Next Button
                        this.lblNextButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex + 2]).Header.ToString();
                    }

                    // Adjust the Text of the Previous Button
                    this.lblPreviousButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex]).Header.ToString();

                    // Adjust the Visible Tab
                    this.tabControlAddPatrons.SelectedIndex = this.tabControlAddPatrons.SelectedIndex + 1;

                    // Ensure the Previous Button is Enabled
                    this.btnPrevious.IsEnabled = true;
                }
            }
        }

        /// <summary>
        /// Reset the fields
        /// </summary>
        private void Reset()
        {
            // Reset the fields to clear them
            this.NewPatron.Reset();

            // Call Validate() on the ErrorProvider so all Invalid markers are removed (being that this.NewPatron.Reset() clears all error messages)
            this.errorProvider1.Validate();

            this.acParent1.SelectedItem = null;
            this.acParent1.Text = "";
            this.acParent2.SelectedItem = null;
            this.acParent2.Text = "";

            // Reset the custom fields
            foreach (NewCustomFieldSource nextEntry in this._customFields)
            {
                nextEntry.Reset();
            }

            // Reset the contact fields
            this._contactMethods.Clear();
            this.dgContactInformation.ItemsSource = this._contactMethods;

            // Move to the first tab
            this.tabControlAddPatrons.SelectedIndex = 0;
        }

        /// <summary>
        /// Handles updating the Forward and Backward Control Buttons when a new tab is selected
        /// on the TabControl.
        /// </summary>
        /// <param name="sender">(TabControl) object sending the event</param>
        /// <param name="e">(SelectionChangedEventArgs) Arguments from the event</param>
        private void tabControlAddPatrons_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // If it's the first Tab
            if (this.tabControlAddPatrons.SelectedIndex == 0)
            {
                // Adjust the Text of the Next & Previous Buttons
                this.lblPreviousButton.Text = ((TabItem)this.tabControlAddPatrons.Items[0]).Header.ToString();
                this.lblNextButton.Text = ((TabItem)this.tabControlAddPatrons.Items[1]).Header.ToString();

                // Adjust the IsEnabled of the Next & Previous Buttons
                this.btnPrevious.IsEnabled = false;
                this.btnNext.IsEnabled = true;
            }

            // If it's an in-between Tab
            if (this.tabControlAddPatrons.SelectedIndex > 0 && this.tabControlAddPatrons.SelectedIndex < (this.tabControlAddPatrons.Items.Count - 1))
            {
                // Adjust the Text of the Next & Previous Buttons
                this.lblPreviousButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex - 1]).Header.ToString();
                this.lblNextButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex + 1]).Header.ToString();

                // Adjust the IsEnabled of the Next & Previous Buttons
                this.btnPrevious.IsEnabled = true;
                this.btnNext.IsEnabled = true;
            }

            // If it's the last Tab
            if (this.tabControlAddPatrons.SelectedIndex == (this.tabControlAddPatrons.Items.Count - 1))
            {
                // Adjust the Text of the Next & Previous Buttons
                this.lblPreviousButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex - 1]).Header.ToString();
                this.lblNextButton.Text = ((TabItem)this.tabControlAddPatrons.Items[this.tabControlAddPatrons.SelectedIndex]).Header.ToString();

                // Adjust the IsEnabled of the Next & Previous Buttons
                this.btnPrevious.IsEnabled = true;
                this.btnNext.IsEnabled = false;
            }
        }

        #endregion

        #region IPage Members

        /// <summary>
        /// Notification when this pageIndex is displayed to the user.
        /// </summary>
        public void Page_Displayed()
        {
            /*
             * Refresh the custom field lists, in case they were edited.
             */
            CustomFieldBusiness customFieldBusiness = CustomFieldBusiness.GetCustomFieldBusiness();

            this._contactFields.Clear();
            this._customFields.Clear();

            // Create the Custom Contact Field Types list for the user to create contact entries from
            this._contactFields = customFieldBusiness.GetCustomFieldTypesByCategory(Constants.CUSTOM_FIELD_PATRON_CONTACT); ;

            // Create the Custom Field Types structures list for the user to fill in
            foreach (CustomFieldType nextField in customFieldBusiness.GetCustomFieldTypesByCategory(Constants.CUSTOM_FIELD_PATRON_CUSTOM))
            {
                NewCustomFieldSource newSource = new NewCustomFieldSource();
                newSource.CustomFieldType = nextField;

                this._customFields.Add(newSource);
            }
        }

        #endregion
    }
}
